package com.example.seckill.service.impl;

import com.example.seckill.common.CodeMsg;
import com.example.seckill.common.RedisKey;
import com.example.seckill.common.Result;
import com.example.seckill.dao.SeckillGoodsMapper;
import com.example.seckill.dao.SeckillOrderMapper;
import com.example.seckill.entity.SeckillGoods;
import com.example.seckill.entity.SeckillOrder;
import com.example.seckill.exception.SeckillException;
import com.example.seckill.mq.SeckillMessage;
import com.example.seckill.service.SeckillService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import jakarta.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.UUID;

@Slf4j
@Service
public class SeckillServiceImpl implements SeckillService {

    @Autowired
    private SeckillGoodsMapper seckillGoodsMapper;
    
    @Autowired
    private SeckillOrderMapper seckillOrderMapper;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RedissonClient redisson;

    @PostConstruct
    public void init() {
        try {
            List<SeckillGoods> goodsList = seckillGoodsMapper.selectList();
            for (SeckillGoods goods : goodsList) {
                // 统一使用Integer类型存储库存
                String stockKey = RedisKey.SECKILL_STOCK_PREFIX + goods.getId();
                redisTemplate.opsForValue().set(stockKey, goods.getStock());
                
                String goodsKey = RedisKey.SECKILL_GOODS_PREFIX + goods.getId();
                redisTemplate.opsForValue().set(goodsKey, goods);
            }
        } catch (Exception e) {
            log.error("商品缓存预热失败", e);
        }
    }

    @Override
    public int getStockFromCache(Long goodsId) {
        String stockKey = RedisKey.SECKILL_STOCK_PREFIX + goodsId;
        Object stock = redisTemplate.opsForValue().get(stockKey);
        
        if (stock == null) {
            RLock lock = redisson.getLock(RedisKey.LOCK_PREFIX + "stock:" + goodsId);
            try {
                if (lock.tryLock(100, TimeUnit.MILLISECONDS)) {
                    try {
                        stock = redisTemplate.opsForValue().get(stockKey);
                        if (stock == null) {
                            SeckillGoods goods = seckillGoodsMapper.selectById(goodsId);
                            if (goods == null) {
                                throw new SeckillException(CodeMsg.GOODS_NOT_EXIST);
                            }
                            stock = goods.getStock();
                            redisTemplate.opsForValue().set(stockKey, stock);
                        }
                    } finally {
                        lock.unlock();
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new SeckillException(CodeMsg.SERVER_ERROR);
            }
        }
        
        if (!(stock instanceof Integer)) {
            throw new SeckillException(CodeMsg.SERVER_ERROR);
        }
        return (Integer) stock;
    }

    @Override
    public Result<SeckillOrder> seckill(Long userId, Long goodsId) {
        String stockKey = RedisKey.SECKILL_STOCK_PREFIX + goodsId;
        
        try {
            if (userId == null || goodsId == null) {
                throw new SeckillException(CodeMsg.PARAM_ERROR);
            }

            // 检查是否重复下单
            String orderKey = RedisKey.SECKILL_ORDER_PREFIX + userId + ":" + goodsId;
            if (Boolean.TRUE.equals(redisTemplate.hasKey(orderKey))) {
                throw new SeckillException(CodeMsg.REPEATE_SECKILL);
            }

            // 预减库存
            getStockFromCache(goodsId);  // 确保缓存存在
            Long result = redisTemplate.opsForValue().decrement(stockKey);
            if (result == null) {
                throw new SeckillException(CodeMsg.SERVER_ERROR);
            }
            int stock = result.intValue();
            if (stock < 0) {
                redisTemplate.opsForValue().increment(stockKey);
                throw new SeckillException(CodeMsg.SECKILL_OVER);
            }

            // 发送消息到MQ并等待确认
            SeckillMessage message = new SeckillMessage(userId, goodsId);
            CorrelationData correlationData = new CorrelationData(UUID.randomUUID().toString());
            correlationData.getFuture().whenComplete((confirm, ex) -> {
                if (ex != null) {
                    log.error("消息发送异常", ex);
                    redisTemplate.opsForValue().increment(stockKey);
                } else if (!confirm.isAck()) {
                    log.error("消息发送失败 - cause: {}", confirm.getReason());
                    redisTemplate.opsForValue().increment(stockKey);
                }
            });
            
            rabbitTemplate.convertAndSend("seckill.queue", message, correlationData);

            return Result.success(null);
        } catch (SeckillException e) {
            throw e;
        } catch (Exception e) {
            log.error("秒杀异常", e);
            throw new SeckillException(CodeMsg.SERVER_ERROR, e);
        }
    }

    @SuppressWarnings("unchecked")
    private List<SeckillGoods> getGoodsListFromCache(String key) {
        Object value = redisTemplate.opsForValue().get(key);
        if (value instanceof List<?> list && !list.isEmpty() && list.get(0) instanceof SeckillGoods) {
            return (List<SeckillGoods>) list;
        }
        return null;
    }

    @Override
    public Result<List<SeckillGoods>> listGoods(Long userId) {
        try {
            String cacheKey = RedisKey.SECKILL_GOODS_PREFIX + "list";
            List<SeckillGoods> goodsList = getGoodsListFromCache(cacheKey);
            
            if (goodsList == null) {
                goodsList = seckillGoodsMapper.selectList();
                if (goodsList == null || goodsList.isEmpty()) {
                    return Result.success(null);
                }
                redisTemplate.opsForValue().set(cacheKey, goodsList, 1, TimeUnit.MINUTES);
            }

            updateGoodsInfo(goodsList, userId);
            return Result.success(goodsList);
        } catch (Exception e) {
            log.error("获取商品列表异常", e);
            throw new SeckillException(CodeMsg.SERVER_ERROR, e);
        }
    }

    // 抽取方法，更新商品信息
    private void updateGoodsInfo(List<SeckillGoods> goodsList, Long userId) {
        // 批量获取库存
        List<String> stockKeys = goodsList.stream()
            .map(goods -> RedisKey.SECKILL_STOCK_PREFIX + goods.getId())
            .toList();
        List<Object> stockList = redisTemplate.opsForValue().multiGet(stockKeys);
        if (stockList == null) {
            return;
        }

        // 如果有用户ID，获取订单状态
        if (userId != null) {
            List<String> orderKeys = goodsList.stream()
                .map(goods -> RedisKey.SECKILL_ORDER_PREFIX + userId + ":" + goods.getId())
                .toList();
            List<Object> orderList = redisTemplate.opsForValue().multiGet(orderKeys);
            if (orderList != null) {
                // 更新购买状态
                for (int i = 0; i < goodsList.size(); i++) {
                    Object orderValue = orderList.get(i);
                    goodsList.get(i).setPurchased(orderValue != null);
                }
            }
        }

        // 更新库存
        for (int i = 0; i < goodsList.size(); i++) {
            Object stockObj = stockList.get(i);
            if (stockObj != null) {
                if (stockObj instanceof Integer) {
                    goodsList.get(i).setStock(((Integer) stockObj).intValue());
                } else if (stockObj instanceof Long) {
                    goodsList.get(i).setStock(((Long) stockObj).intValue());
                }
            }
        }
    }

    @Override
    public Result<SeckillOrder> getOrder(Long orderId) {
        SeckillOrder order = seckillOrderMapper.selectById(orderId);
        if (order == null) {
            return Result.error(CodeMsg.SERVER_ERROR);
        }
        return Result.success(order);
    }

    @Override
    public Result<Boolean> checkPurchased(Long userId, Long goodsId) {
        try {
            // 1. 先从缓存查询
            String orderKey = RedisKey.SECKILL_ORDER_PREFIX + userId + ":" + goodsId;
            Object cacheResult = redisTemplate.opsForValue().get(orderKey);
            
            if (cacheResult != null) {
                return Result.success(true);
            }
            
            /*
            // 2. 缓存未命中，查询数据库
            SeckillOrder order = seckillOrderMapper.selectByUserIdAndGoodsId(userId, goodsId);
            
            if (order != null) {
                // 重新放入缓存，设置较短的过期时间
                redisTemplate.opsForValue().set(orderKey, order.getId(), 5, TimeUnit.MINUTES);
                return Result.success(true);
            }
            */
            
            return Result.success(false);
        } catch (Exception e) {
            log.error("检查用户购买记录异常 - userId: {}, goodsId: {}", userId, goodsId, e);
            return Result.error(CodeMsg.SERVER_ERROR);
        }
    }
}
